package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.api.ChannelFeignClient;
import com.heima.article.mapper.ArticleHomeMapper;
import com.heima.article.service.HotArticleService;
import com.heima.article.vo.HotArticleVo;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.mess.ArticleVisitStreamMess;
import com.heima.model.wemedia.pojos.WmChannel;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author DiXiaoNie
 * @since 2023/1/6 15:00
 */
@Service
public class HotArticleServiceImpl implements HotArticleService {
    @Resource
    private ArticleHomeMapper articleMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ChannelFeignClient client;

    /**
     * 计算热点文章
     *
     * @author DiXiaoNie
     * @date 2023/01/06
     */
    @Override
    public void computeHotArticle() {
        //1.查询当前日期前五天的列表
        // TODO: 2023/1/6 方式一
/*        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -5);
        Date last5Day = calendar.getTime();*/

        // TODO: 2023/1/6 方式二
        Date last5Day = DateTime.now().minusDays(5).toDate();
        List<ApArticle> apArticleList = this.articleMapper.loadArticleLast5DayList(last5Day);

        //2.对文章进行分值计算
        List<HotArticleVo> hotArticleVoList = calculationArticleSource(apArticleList);
        //3.根据频道，取出前三十天分值较高的数据存入到redis中
        // 远程调用获取频道列表
        ResponseResult responseResult = client.channels();
        if (responseResult.getCode() == 200) {
            List<WmChannel> channelsList = (List<WmChannel>) responseResult.getData();
            //检索出每个频道的文章
            List<HotArticleVo> finalHotArticleVoList = hotArticleVoList;
            channelsList.forEach(wmChannel -> {
                List<HotArticleVo> channelHotArticleList = finalHotArticleVoList.stream()
                        .filter(hotArticleVo -> hotArticleVo.getChannelId().equals(wmChannel.getId())).collect(Collectors.toList());
                //存到redis中
                cacheToRedis(channelHotArticleList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + wmChannel.getId());
            });
        }

        //4.推荐（全部文章）取出前三十天分值较高的数据存入到redis中
        //         String key = ArticleConstants.HOT_ARTICLE_FIRST_PAGE + "__all__";
        this.cacheToRedis(hotArticleVoList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + "__all__");
    }

    /**
     * 更新文章的分值，同时更新缓存中的热点文章数据
     *
     * @param mess 混乱
     * @author DiXiaoNie
     * @date 2023/01/07
     */
    @Override
    public void updateScore(ArticleVisitStreamMess mess) {
        //1.修改ap_article表中的行为数量
        ApArticle apArticle = this.articleMapper.selectById(mess.getArticleId());
        if (apArticle == null) {
            return;
        }
        apArticle.setCollection(apArticle.getCollection() == null ? 0 : apArticle.getCollection() + mess.getCollect());
        apArticle.setComment(apArticle.getComment() == null ? 0 : apArticle.getComment() + mess.getComment());
        apArticle.setViews(apArticle.getViews() == null ? 0 : apArticle.getViews() + mess.getView());
        apArticle.setLikes(apArticle.getLikes() == null ? 0 : apArticle.getLikes() + mess.getLike());
        this.articleMapper.updateById(apArticle);
        //2.重新计算分值
        Integer score = this.computeHotArticleScore(apArticle);
        score = score * 3;

        //3.频道。替换redis中的数据
        replaceDataToRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());

        //4.推荐（全部文章），替换redis中的数据
        replaceDataToRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + "__all__");
    }

    /**
     * 替换数据到redis,
     *
     * @param apArticle 美联社文章
     * @param score     分数
     * @param key       redisKey
     * @author DiXiaoNie
     * @date 2023/01/07
     */
    private void replaceDataToRedis(ApArticle apArticle, Integer score, String key) {
        String hotArticleVoListStr = this.redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(hotArticleVoListStr)) {
            return;
        }
        //定义一个标识， true表示不存在  false表示存在
        boolean flag = true;

        List<HotArticleVo> hotArticleVoList = JSONArray.parseArray(hotArticleVoListStr, HotArticleVo.class);
        if (hotArticleVoList != null && hotArticleVoList.size() > 0) {
            for (HotArticleVo hotArticleVo : hotArticleVoList) {
                //当前缓存中是否存在该文章
                if (hotArticleVo.getId().equals(apArticle.getId())) {
                    hotArticleVo.setScore(score);
                    flag = false;
                    break;
                }
            }
            if (flag) {
                if (hotArticleVoList.size() >= 30) {
                    hotArticleVoList = hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
                    HotArticleVo lastHot = hotArticleVoList.get(hotArticleVoList.size() - 1);
                    if (lastHot.getScore() < score) {
                        hotArticleVoList.remove(lastHot);
                        HotArticleVo hot = new HotArticleVo();
                        BeanUtils.copyProperties(apArticle, hot);
                        hot.setScore(score);
                        hotArticleVoList.add(hot);
                    }


                } else {
                    HotArticleVo hot = new HotArticleVo();
                    BeanUtils.copyProperties(apArticle, hot);
                    hot.setScore(score);
                    hotArticleVoList.add(hot);
                }
            }
            hotArticleVoList = hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
            //封装到redis中
            this.redisTemplate.opsForValue().set(key, JSON.toJSONString(hotArticleVoList));
        }
    }

    private void cacheToRedis(List<HotArticleVo> channelHotArticleList, String key) {
        channelHotArticleList = channelHotArticleList.stream()
                //按照分值排序+取出前三十条分值最高的文章
                .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                //取出前三十条数据
                .limit(30)
                .collect(Collectors.toList());
        //存到redis中
        this.redisTemplate.opsForValue().set(key, JSON.toJSONString(channelHotArticleList));
    }

    /**
     * 计算文章分值
     *
     * @param apArticleList 美联社文章列表
     * @return {@link List }<{@link HotArticleVo }>
     * @author DiXiaoNie
     * @date 2023/01/06
     */
    private List<HotArticleVo> calculationArticleSource(List<ApArticle> apArticleList) {
        List<HotArticleVo> hotArticleVoList = new ArrayList<>();
        apArticleList.forEach(apArticle -> {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle, hotArticleVo);
            //计算分值
            Integer score = computeHotArticleScore(apArticle);

            hotArticleVo.setScore(score);
            hotArticleVoList.add(hotArticleVo);
        });
        return hotArticleVoList;
    }

    /**
     * 计算热点文章分值
     *
     * @param apArticle 美联社文章
     * @return {@link Integer }
     * @author DiXiaoNie
     * @date 2023/01/06
     */
    private Integer computeHotArticleScore(ApArticle apArticle) {
        //声名一个变量

        Integer score = 0;
        //点赞
        if (apArticle.getLikes() != null) {
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        //阅读
        if (apArticle.getViews() != null) {
            score += apArticle.getViews();
        }
        //评论
        if (apArticle.getComment() != null) {
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        //收藏
        if (apArticle.getCollection() != null) {
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }

        return score;
    }
}
